function Clock(func, period) {
    this.timer = null;
    this.func = func;
    this.period = period;

    this.setPeriod = function (period) {
        this.period = period;
        if (this.timer !== null) {
            this.stop();
            this.start();
        }
    };

    this.start = function () {
        if (this.timer === null) {
            this.timer = setInterval(this.func, this.period);
        }
    };

    this.stop = function () {
        if (this.timer !== null) {
            clearTimeout(this.timer);
            this.timer = null;
        }
    };
}

function protoSupported() {
    function Test(){}
    Test.prototype = "aoeu";
    let test = new Test();
    if (test.__proto__ != "aoeu"){
        return false;
    }

    let test2 = new Test();
    test2.__proto__ = [];
    if (! test2 instanceof Array) {
        return false;
    }
    return true;
}
function random(minNum,maxNum){
    let ret = 0;
    switch(arguments.length){ 
        case 1: 
            ret = parseInt(Math.random()*minNum+1,10);
            break;
        case 2: 
            ret = parseInt(Math.random()*(maxNum-minNum+1)+minNum,10);
            break;
        default: 
            ret = 0;
    }
    return ret;
}

function randomColor(city, num){
    let color = "";
    let cell;
    let found = false;
    while(!found){
        for(let i=0; i < 6; i++){
            cell = Math.random() * 16 | 0;
            if(cell < 5){
                cell += 5;
            }
            color += cell.toString(16);
        }
        if(color == '#000000'){
            continue;
        }
        found = true;
        for(let i=0; i <= num; i++){
            if(city[i].color == color){
                found = false;
                break;
            }
        }
    }
    return "#" + color;
};

function fixDirection(direct, x, y, maxwidth, maxheight, referee){
    let dx = x;
    let dy = y;
    switch(direct){
        case referee.up:
            dy--;
            dy = dy < 0 ? maxheight - 1 : dy;
            break;
        case referee.down:
            dy++;
            dy = dy == maxheight ? 0 : dy;
            break;
        case referee.left:
            dx--;
            dx = dx < 0 ? maxwidth - 1 : dx;
            break;
        case referee.right:
            dx++;
            dx = dx == maxwidth ? 0 : dx;
            break;
    }
    return {
        sx: x,
        sy: y,
        dx: dx,
        dy: dy
        };
};

function drawArc(ctx, x, y, width, height, shadow, color, radius){
    let px = Math.floor(x + width/2);
    let py = Math.floor(y + height/2);
    ctx.shadowColor = shadow;
    ctx.shadowBlur = 10;
    ctx.beginPath();
    ctx.arc(px,py,radius,0, 2* Math.PI);
    ctx.closePath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = color;
    ctx.stroke();
};
function drawText(ctx, x, y, width, height, text, shadow, color){
    let px = Math.floor(x + (1 * width /2));
    let py = Math.floor(y + (3 * height/5))
    ctx.shadowColor = shadow;
    ctx.shadowBlur = 10;
    ctx.font = "10px Arial,sans-serif";
    ctx.fillStyle = color;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(text, px, py);
};

function drawTriangle(ctx, x, y, width, height, model, shadow, color){
    let point = [];
    let px, py;
    switch(model){
        case 0:
            px = Math.floor(x + width / 2) ;
            py = y;
            point.push({x:px + 1, y:py - 1});
            px = Math.floor(x + width);
            py = Math.floor(y + height);
            point.push({x:px + 1, y:py - 1});
            px = Math.floor(x);
            point.push({x:px + 1, y:py -  1});
            break;
        case 1:
            px = Math.floor(x);
            py = Math.floor(y);
            point.push({x:px + 1, y:py - 1});
            px = Math.floor(x + width);
            point.push({x:px + 1, y:py - 1});
            px = Math.floor(x + width / 2);
            py = Math.floor(y + height);
            point.push({x:px + 1, y:py - 1});
            break;
        case 2:
            px = Math.floor(x);
            py = Math.floor(y);
            point.push({x:px + 1, y:py - 1});
            px = Math.floor(x + width);
            py = Math.floor(y + height);
            point.push({x:px + 1, y:py - 1});
            px = Math.floor(x + width);
            py = Math.floor(y);
            point.push({x:px + 1, y:py - 1});
            px = Math.floor(x);
            py = Math.floor(y + height);
            point.push({x:px + 1, y:py - 1});
            break;
    }
    ctx.beginPath();
    ctx.moveTo(point[0].x, point[0].y);
    for(let i=1; i<point.length;i++){
        ctx.lineTo(point[i].x, point[i].y);
    }
    ctx.closePath();
    ctx.shadowColor = shadow;
    ctx.shadowBlur = 10;
    ctx.lineWidth = 2;
    ctx.strokeStyle = color;
    ctx.stroke();
}

let boom_timer=null;
let boom_colorArr = ["#ff0", "#f00", "#0ff", "#f0f"];
let boom_data = [];
let boom_ctx;
let boom_width, boom_height, boom_x, boom_y, boom_num;

function drawBoom(ctx, x, y, num, width, height){
    boom_ctx = ctx;
    boom_width = width;
    boom_height = height;
    boom_x = x;
    boom_y = y;
    boom_num = num;
    if(boom_data.length < boom_num * 10){
        let arr = Array(num).fill(1).map(()=>getData(x,y));
        boom_data = [...boom_data,...arr];
        boom();
    }
}

function boom(){
    boom_timer && window.cancelAnimationFrame(boom_timer);
    boom_timer = window.requestAnimationFrame(boom);
    boom_ctx.clearRect(boom_x, boom_y, boom_width, boom_height);
        animate(boom_data,function(){
            if(!boom_data.length){
                window.cancelAnimationFrame(boom_timer);
            }
        });
}
function animate(arr,fn){
    arr.forEach((item,index)=>{
        let {x,y,r,c,s} = item;
        x += s.x;
        y += s.y;
        r -=s.r;
        if(r <= 0){
            arr.splice(index,1);
            fn&&fn();
        }else{
            arr[index] = {x, y, r,c,s};
            circle(x,y,r,c);
        }
    })
}

function getData(x, y){
    let r =  10;
    let c = boom_colorArr[random(1, boom_colorArr.length) - 1];
    let s = {
        x: random(-1, 1),
        y: random(-1, 1),
        r: 1
    }
    return {x,y,r,c,s}
}

function circle(x, y, r, color = "#fff") {
    boom_ctx.beginPath();
    boom_ctx.fillStyle = color;
    boom_ctx.arc(x, y, r, 0, Math.PI * 2);
    boom_ctx.fill();
    boom_ctx.closePath();
}